/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Resolve classes, methods, fields, and strings.
 *
 * According to the VM spec (v2 5.5), classes may be initialized by use
 * of the "new", "getstatic", "putstatic", or "invokestatic" instructions.
 * If we are resolving a static method or static field, we make the
 * initialization check here.
 *
 * (NOTE: the verifier has its own resolve functions, which can be invoked
 * if a class isn't pre-verified.  Those functions must not update the
 * "resolved stuff" tables for static fields and methods, because they do
 * not perform initialization.)
 */

#include <stdlib.h>
#include <string>
#include "Object.h"
#include "Resolve.h"
#include "Class.h"
#include "DvmFunctionTable.h"


/*
 * Find the class corresponding to "classIdx", which maps to a class name
 * string.  It might be in the same DEX file as "referrer", in a different
 * DEX file, generated by a class loader, or generated by the VM (e.g.
 * array classes).
 *
 * Because the DexTypeId is associated with the referring class' DEX file,
 * we may have to resolve the same class more than once if it's referred
 * to from classes in multiple DEX files.  This is a necessary property for
 * DEX files associated with different class loaders.
 *
 * We cache a copy of the lookup in the DexFile's "resolved class" table,
 * so future references to "classIdx" are faster.
 *
 * Note that "referrer" may be in the process of being linked.
 *
 * Traditional VMs might do access checks here, but in Dalvik the class
 * "constant pool" is shared between all classes in the DEX file.  We rely
 * on the verifier to do the checks for us.
 *
 * Does not initialize the class.
 *
 * "fromUnverifiedConstant" should only be set if this call is the direct
 * result of executing a "const-class" or "instance-of" instruction, which
 * use class constants not resolved by the bytecode verifier.
 *
 * Returns NULL with an exception raised on failure.
 */
ClassObject *dvmResolveClass(const ClassObject *referrer, u4 classIdx,
                             bool fromUnverifiedConstant) {
    return dvmFunctionTables.dvmResolveClass(referrer, classIdx, fromUnverifiedConstant);
}


/*
 * Find the method corresponding to "methodRef".
 *
 * We use "referrer" to find the DexFile with the constant pool that
 * "methodRef" is an index into.  We also use its class loader.  The method
 * being resolved may very well be in a different DEX file.
 *
 * If this is a static method, we ensure that the method's class is
 * initialized.
 */
Method *dvmResolveMethod(const ClassObject *referrer, u4 methodIdx,
                         MethodType methodType) {
    return dvmFunctionTables.dvmResolveMethod(referrer, methodIdx, methodType);
}

/*
 * Resolve an interface method reference.
 *
 * Returns NULL with an exception raised on failure.
 */
Method *dvmResolveInterfaceMethod(const ClassObject *referrer, u4 methodIdx) {
    return dvmFunctionTables.dvmResolveInterfaceMethod(referrer, methodIdx);
}

/*
 * Resolve an instance field reference.
 *
 * Returns NULL and throws an exception on error (no such field, illegal
 * access).
 */
InstField *dvmResolveInstField(const ClassObject *referrer, u4 ifieldIdx) {
    return dvmFunctionTables.dvmResolveInstField(referrer, ifieldIdx);
}

/*
 * Resolve a static field reference.  The DexFile format doesn't distinguish
 * between static and instance field references, so the "resolved" pointer
 * in the Dex struct will have the wrong type.  We trivially cast it here.
 *
 * Causes the field's class to be initialized.
 */
StaticField *dvmResolveStaticField(const ClassObject *referrer, u4 sfieldIdx) {
    return dvmFunctionTables.dvmResolveStaticField(referrer, sfieldIdx);
}


/*
 * Resolve a string reference.
 *
 * Finding the string is easy.  We need to return a reference to a
 * java/lang/String object, not a bunch of characters, which means the
 * first time we get here we need to create an interned string.
 */
StringObject *dvmResolveString(const ClassObject *referrer, u4 stringIdx) {
    return dvmFunctionTables.dvmResolveString(referrer, stringIdx);
}

/*
 * For debugging: return a string representing the methodType.
 */
const char *dvmMethodTypeStr(MethodType methodType) {
    switch (methodType) {
        case METHOD_DIRECT:
            return "direct";
        case METHOD_STATIC:
            return "static";
        case METHOD_VIRTUAL:
            return "virtual";
        case METHOD_INTERFACE:
            return "interface";
        case METHOD_UNKNOWN:
            return "UNKNOWN";
    }
    assert(false);
    return "BOGUS";
}
